function Promise(callback) {
  this.status = 'PENDING'
  const resolve = value => {
    if (this.status != 'PENDING') return
    this.value = value
    this.status = 'FULLFILED'
    setTimeout(() => {
      this.resolveFn?.(value)
    })
  }
  const reject = reason => {
    if (this.status != 'PENDING') return
    this.reason = reason
    this.status = 'REJECTED'
    setTimeout(() => {
      this.rejectFn?.(reason)
    })
  }
  try {
    callback(resolve, reject)
  } catch (e) {
    reject(e)
  }
}

Promise.prototype.then = function (resolve, reject) {
  return new Promise((nextResolve, nextReject) => {
    resolve = resolve || Promise.resolve
    reject = reject || Promise.reject
    nextResolve = nextResolve || Promise.resolve
    nextReject = nextReject || Promise.reject

    function handleResult(result) {
      if (result instanceof Promise) {
        if (result.status == 'FULLFILED') {
          nextResolve(result.value)
        } else if (result.status == 'REJECTED') {
          nextReject(result.reason)
        }
      }
      nextResolve(result)
    }

    this.resolveFn = value => {
      const result = resolve(value)
      handleResult(result)
    }

    this.rejectFn = reason => {
      const result = reject(reason)
      handleResult(result)
    }
  })
}

Promise.prototype.catch = function (reject) {
  return this.then(null, reject)
}

Promise.prototype.finally = function (fn) {
  return this.then(fn, fn)
}

Promise.prototype.all = function (array) {
  return new Promise((resolve, reject) => {
    const obj = Object.create(null)
    array.forEach((item, index) => {
      item.then(
        value => {
          obj[index] = value
          if (Object.keys(obj).length === array.length) {
            resolve(Object.values(obj))
          }
        },
        reason => {
          reject(reason)
        }
      )
    })
  })
}

Promise.prototype.allSettled = function (array) {
  return new Promise((resolve, reject) => {
    const obj = Object.create(null)
    array.forEach((item, index) => {
      item.then(
        value => {
          obj[index] = value
          if (Object.keys(obj).length === array.length) {
            resolve(Object.values(obj))
          }
        },
        reason => {
          obj[index] = reason
          if (Object.keys(obj).length === array.length) {
            reject(Object.values(obj))
          }
        }
      )
    })
  })
}

Promise.prototype.any = function (array) {
  return new Promise((resolve, reject) => {
    array.forEach(item => {
      item.then(resolve)
    })
  })
}

Promise.prototype.race = function (array) {
  return new Promise((resolve, reject) => {
    array.forEach(item => {
      item.then(resolve, reject)
    })
  })
}

Promise.prototype.resolve = function (value) {
  return new Promise(resolve => {
    resolve(value)
  })
}

Promise.prototype.reject = function (reason) {
  return new Promise(reject => {
    reject(reason)
  })
}
